javascript经典面试题理解this

javascript this 经典面试题

1
2
3
4
5
6
7
8
9
10
function Foo(){
getName = function(){console.log("1");};//这个不属于Foo的属性
return this ;
//如果作为构造函数,那么返回的this就是实例化对象,
//如果作为函数直接执行,那么返回的this就是全局的window对象
}
Foo.getName = function(){console.log("2"); };
Foo.prototype.getName = function(){ console.log("3");};
var getName =function(){console.log("4");};
function getName(){console.log("5");};

预解析之后

1
2
3
4
5
6
7
8
9
10
var getName;//只提升变量声明
function getName(){console.log("5");};//提升函数声明,覆盖变量var声明
function Foo(){
getName = function(){console.log("1");};//这个不属于Foo的属性
return this ;//如果作为构造函数,那么返回的this就是实例化对象,如果作为函数直接执行,那么返回的this就是全局的window对象
}
Foo.getName = function(){console.log("2"); };
Foo.prototype.getName = function(){ console.log("3");};
getName =function(){console.log("4");};

可以在控制台输出看下数据结构

1
2
3
console.dir(Foo);
var res = Foo.getName();//注意没有返回值,如果将Foo看成对象,
console.log(res);

看下面的求值过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Foo.getName();//2
getName();//4
Foo().getName();
//1 先执行了Foo() 函数,Foo函数第一句,getName没有用var声明,改变了输出4的getName,变为输出1
//2 第二句 返回了this,代表当前指向环境的window;相当于执行了 window.getName();
getName();//1 直接调用getName ,上面一行代码改变后的结果
//运算符的优先级 () > 成员访问 . > new 操作符
new Foo.getName();//2 new一个构造函数的时候,构造函数内部的代码会一行一行执行;
// 等价于 new (Foo.getName)();
new Foo().getName();//3 Foo作为构造哦函数,没有给实例化的对象添加任何属性,只能去原型上找
// 等价于 (new Foo()).getName();
new new Foo().getName();//3
// 等价于 new (new Foo().getName)();

————————————- = 运算符面试题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
面试题
*/
// 基本类型和引用类型
// 引用类型变量和对象属性(在内存实际上就是内存地址)
var a = {n:1};
var b = a;
a.x = a = {n:2};//运算符的优先级 .的优先级最高 赋值操作是从右向左运算的
console.log(a.x);//undefined
console.log(b.x);//{n:2}
/*
我们可以先尝试交换下连等赋值顺序(a = a.x = {n: 2};),可以发现输出不变,即顺序不影响结果。
那么现在来解释对象连等赋值的问题:按照es5规范,题中连等赋值等价于
a.x = (a = {n: 2});,按优先获取左引用(lref),然后获取右引用(rref)的顺序,a.x和a中的a都指向了{n: 1}。至此,至关重要或者说最迷惑的一步明确。(a = {n: 2})执行完成后,变量a指向{n: 2},并返回{n: 2};接着执行a.x = {n: 2},这里的a就是b(指向{n: 1}),所以b.x就指向了{n: 2}。
*/